#pragma once

#include <mysql/mysql.h>
#include <queue>
#include <mutex>
#include <memory>
#include <condition_variable>
#include <chrono>

using namespace std;

/**
 * 1. 动态扩容
 * 2. 检查连接
 * 3. 智能指针要自动回收资源
 */

class ConnectionPool
{
private:
	// 默认构造函数是私有的，确保只能通过getInstance()来获取实例。
	ConnectionPool() = default;

	/**
	 * @brief 创建新的数据库连接
	 * 连接数不足 创建新连接
	 */
	MYSQL* createConnection();

	/**
	 * @brief 检查连接有效性
	 * 查询来验证
	 * @param conn 需要验证和检查的连接
	 */
	bool validateConnection(MYSQL* conn);
	
	// 连接池内部使用的队列，存储可用的数据库连接。 析构的话不断开连接池 而是将不使用的连接进队列 获取连接也是从队列中取
	queue<MYSQL*> connQueue_;
	// mutex_ 这个成员变量，即使在 const 成员函数中，也能被修改
	mutable mutex mutex_;
	// 在获取连接时进行等待的条件变量。
	condition_variable cond_;
	string host_, user_, pwd_, dbName_;
	unsigned int port_;
	int maxConn_;
	int curConn_ = 0;
	int connTimeout_;
public:
 /**
     * @brief 获取ConnectionPool类的单例实例。
     * 使用单例模式来保证  整个程序中只会有一个连接池实例。
     * @return ConnectionPool* 单例实例
     */
	static ConnectionPool* getInstance();

	/**
	 * @brief 初始化连接池
	 * 基本配置
	 * @param port 默认端口 实现中不能指定
	 */
	void init(const string& host, const string& user, const string& pwd, const string& dbname, unsigned int port = 3306, int maxConn = 10, int timeout = 5000);

	/**
	 * @brief 获取 一个 数据库连接
	 * 如果连接池中有空闲连接，返回该连接。如果没有空闲连接，且当前连接数未达到最大连接数，则会创建一个新连接并返回。若超过超时时间仍未获取到连接，返回 nullptr
	 * @param 超时时间 3000 ms
	 * @return shared_ptr<MYSQL>类型 数据库连接
	 */
	shared_ptr<MYSQL> getConnection(int timeout = 3000);

	/**
	 * 状态结构体
	 * @brief 当前连接池的连接总数和空闲连接数
	 * @return PoolStats 当前连接池状态，包括连接总数和空闲连接数
	 */
	struct PoolStats
	{
		int total;
		int idle;
	};
	PoolStats getStats() const;
};


